﻿namespace ESheep.Sheep.World
{
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;

    using Creature;

    internal class Border : IBorder
    {
        private List<Line> edgeLines;

        public Border(IEnumerable<Rectangle> screenRectangles)
        {
           ScreenToAdge(screenRectangles);
        }

        private void ScreenToAdge(IEnumerable<Rectangle> screenRectangles)
        {
            edgeLines = new List<Line>();

            foreach (var rectangle in screenRectangles)
            {
                AddLine(new Line
                {
                    A1 = new Point(rectangle.X, rectangle.Y),
                    A2 = new Point(rectangle.X, rectangle.Y + rectangle.Height)
                });

                AddLine(new Line
                {
                    A1 = new Point(rectangle.X, rectangle.Y),
                    A2 = new Point(rectangle.X + rectangle.Width, rectangle.Y)
                });

                AddLine(new Line
                {
                    A1 = new Point(rectangle.X + rectangle.Width, rectangle.Y),
                    A2 = new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height)
                });

                AddLine(new Line
                {
                    A1 = new Point(rectangle.X, rectangle.Y + rectangle.Height),
                    A2 = new Point(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height)
                });
            }
        }

        void AddLine(Line line)
        {
            // удалить повторяющиеся (соединения одинаковых экранов стоящих рядом)
            if (edgeLines.Any(a => a.A1 == line.A1 && a.A2 == line.A2 || a.A1 == line.A2 && a.A2 == line.A1))
            {
                edgeLines.RemoveAll(a => a.A1 == line.A1 && a.A2 == line.A2 || a.A1 == line.A2 && a.A2 == line.A1);
                return;
            }

            // объеденить отрезки
            foreach (var line2 in edgeLines)
            {
                if (line.A1.Y == line.A2.Y &&
                    line2.A2.Y == line2.A1.Y &&
                    line2.A2.Y == line.A2.Y)
                {
                    if (line.A1.X == line2.A2.X)
                    {
                        line2.A2 = new Point(line.A2.X, line.A2.Y);
                        return;
                    }

                    if (line.A2.X == line2.A1.X)
                    {
                        line2.A1 = new Point(line.A1.X, line.A1.Y);
                        return;
                    }
                }

                if (line.A1.X == line.A2.X &&
                    line2.A2.X == line2.A1.X &&
                    line2.A2.X == line.A2.X)
                {
                    if (line.A1.Y == line2.A2.Y)
                    {
                        line2.A2 = new Point(line.A2.X, line.A2.Y);
                        return;
                    }

                    if (line.A2.Y == line2.A1.Y)
                    {
                        line2.A2 = new Point(line.A2.X, line.A2.Y);
                        return;
                    }

                    if (line.A1.Y > line2.A1.Y)
                    {
                        edgeLines.Add(new Line
                        {
                            A1 = line2.A2,
                            A2 = line.A2
                        });
                        line2.A2 = new Point(line.A1.X, line.A1.Y);
                        return;
                    }

                    if (line.A1.Y < line2.A1.Y)
                    {
                        edgeLines.Add(new Line
                        {
                            A1 = line.A1,
                            A2 = line2.A1
                        });
                        line2.A1 = new Point(line.A2.X, line.A2.Y);
                        return;
                    }
                }
            }

            edgeLines.Add(line);
        }

        public bool StepIsBlocked(Creature context, double dx, double dy, int width, int height, bool justScreen = false)
        {
            if (dx > 0)
            {
                if (this.IsWindowAt((int)(context.X + dx + width), (int)(context.Y + dy), justScreen))
                {
                    return true;
                }

                if (this.IsWindowAt((int)(context.X + dx + width), (int)(context.Y + dy + height), justScreen))
                {
                    return true;
                }
            }

            if (dx < 0)
            {
                if (this.IsWindowAt((int)(context.X + dx), (int)(context.Y + dy), justScreen))
                {
                    return true;
                }

                if (this.IsWindowAt((int)(context.X + dx), (int)(context.Y + dy + height), justScreen))
                {
                    return true;
                }
            }

            if (dy > 0)
            {
                if (this.IsWindowAt((int)(context.X + dx), (int)(context.Y + dy + height), justScreen))
                {
                    return true;
                }

                if (this.IsWindowAt((int)(context.X + dx + width), (int)(context.Y + dy + height), justScreen))
                {
                    return true;
                }
            }

            if (dy < 0)
            {
                if (this.IsWindowAt((int)(context.X + dx), (int)(context.Y + dy), justScreen))
                {
                    return true;
                }

                if (this.IsWindowAt((int)(context.X + dx), (int)(context.Y + dy + height), justScreen))
                {
                    return true;
                }
            }

            return false;
        }

        private bool IsWindowAt(int mx, int my, bool justScreen = false)
        {
            foreach (var line in edgeLines.ToList())
            {
                if (line.A1.X == line.A2.X && line.A2.X == mx &&
                    line.A1.Y <= my && line.A2.Y >= my)
                {
                    return true;
                }

                if (line.A1.Y == line.A2.Y && line.A2.Y == my &&
                    line.A1.X <= mx && line.A2.X >= mx)
                {
                    return true;
                }
            }

            // TODO : uncomment if want sheep to jump on the windows
            //if (justScreen) return false;
            //var r = new Rect();
            //var h = WinApi.GetWindowFromPoint(mx, my);
            //if (h != IntPtr.Zero)
            //{
            //    WinApi.GetWindowRectangle(h, ref r);
            //    if (
            //            (
            //                ((mx == r.Left) || (mx == r.Right)) &&
            //                ((my >= r.Top) && (my <= r.Bottom))
            //            )
            //            ||
            //            (
            //                ((mx >= r.Left) && (mx <= r.Right)) &&
            //                ((my == r.Top) || (my == r.Bottom))
            //            )
            //        )
            //    {
            //        return true;
            //    }
            //}

            return false;
        }
    }
}
